package auth

import (
	"douhu_backend/internal/errors"
	"douhu_backend/internal/infra/logger"
	"time"
)

// RefreshTokenRequest 刷新Token请求
type RefreshTokenRequest struct {
	RefreshToken string `json:"refresh_token" validate:"required"`
}

// TokenData Token刷新成功返回的数据
type TokenData struct {
	AccessToken      string    `json:"access_token"`
	RefreshToken     string    `json:"refresh_token"`
	AccessExpiresAt  time.Time `json:"access_expires_at"`
	RefreshExpiresAt time.Time `json:"refresh_expires_at"`
}

// RefreshAccessToken 使用refresh token刷新access token
// 返回 (*TokenData, error)
// - 成功: 返回 (TokenData, nil)
// - 失败: 返回 (nil, ServiceError)
func (s *Service) RefreshAccessToken(req *RefreshTokenRequest) (*TokenData, error) {
	// 1. 解析 refresh token
	jwtService := s.JWT()
	claims, err := jwtService.ParseToken(req.RefreshToken)
	if err != nil {
		logger.Errorf("Parse refresh token failed: %v", err)
		return nil, errors.ErrTokenInvalid
	}

	// 2. 验证是否为 refresh token
	if claims.TokenType != "refresh" {
		return nil, errors.ErrTokenInvalid
	}

	// 3. 从数据库验证 refresh token 是否有效
	daoManager := s.manager.GetDAOManager()
	authDAO := daoManager.Auth

	isValid, err := authDAO.ValidateRefreshToken(claims.UserID, req.RefreshToken)
	if err != nil {
		logger.Errorf("Validate refresh token from DB failed: %v", err)
		return nil, errors.ErrSystem
	}

	if !isValid {
		return nil, errors.ErrTokenRevoked
	}

	// 4. 生成新的 Token 对
	newTokenPair, err := jwtService.GenerateTokenPair(claims.UserID, claims.Phone)
	if err != nil {
		logger.Errorf("Generate new token pair failed: %v", err)
		return nil, errors.ErrSystem
	}

	// 5. 更新数据库中的 refresh token
	if err := authDAO.UpdateUserRefreshToken(claims.UserID, newTokenPair.RefreshToken, newTokenPair.RefreshExpiresAt); err != nil {
		logger.Errorf("Update refresh token in DB failed: %v", err)
	}

	logger.Infof("Refresh token success: user_id=%d", claims.UserID)

	// 返回新的 Token 数据
	return &TokenData{
		AccessToken:      newTokenPair.AccessToken,
		RefreshToken:     newTokenPair.RefreshToken,
		AccessExpiresAt:  newTokenPair.AccessExpiresAt,
		RefreshExpiresAt: newTokenPair.RefreshExpiresAt,
	}, nil
}
